using System;
using System.IO;
using System.Net;
using System.Reflection;
using CodePlex.TfsLibrary.Utility;
using CodePlex.UnitTestUtility;
using Xunit;

namespace CodePlex.TfsLibrary.ClientEngine
{
    public class TfsWorkspaceManagerTest
    {
        static readonly FileSystem fileSystem = new FileSystem();

        [Fact, TempUserPath]
        public void CanCreateWorkspace()
        {
            NetworkCredential creds = new NetworkCredential("joe", "bob");
            TestableTfsWorkspaceManager manager = TestableTfsWorkspaceManager.Create();
            string workspaceName;

            using (TfsWorkspace workspace = manager.CreateWorkspace("http://tfsUrl", creds))
                workspaceName = workspace.Name;

            Assert.Equal("http://tfsUrl", manager.SourceControlService.CreateWorkspace_TfsUrl);
            Assert.Same(creds, manager.SourceControlService.CreateWorkspace_Credentials);
            Assert.Equal(workspaceName, manager.SourceControlService.CreateWorkspace_WorkspaceName);
        }

        [Fact, TempUserPath]
        public void CleansUpWorkspacesNextTimeWhenFailuresOccur()
        {
            string workspaceName;
            NetworkCredential creds = new NetworkCredential("joe", "bob");
            TestableTfsWorkspaceManager manager = TestableTfsWorkspaceManager.Create();
            manager.SourceControlService.DeleteWorkspace__ThrowException = true;
            using (TfsWorkspace workspace = manager.CreateWorkspace("http://tfsUrl", creds))
                workspaceName = workspace.Name;

            TestableTfsWorkspaceManager manager2 = TestableTfsWorkspaceManager.Create();

            using (manager2.CreateWorkspace("http://tfsUrl", creds))
            {
                Assert.Equal(workspaceName, manager2.SourceControlService.DeleteWorkspace_WorkspaceName);
            }
        }

        [Fact, TempUserPath]
        public void DisposingTfsWorkspaceDeletesWorkspace()
        {
            NetworkCredential creds = new NetworkCredential("joe", "bob");
            TestableTfsWorkspaceManager manager = TestableTfsWorkspaceManager.Create();
            string workspaceName;

            using (TfsWorkspace workspace = manager.CreateWorkspace("http://tfsUrl", creds))
                workspaceName = workspace.Name;

            Assert.Equal(workspaceName, manager.SourceControlService.DeleteWorkspace_WorkspaceName);
            Assert.Same(creds, manager.SourceControlService.DeleteWorkspace_Credentials);
            Assert.Equal("http://tfsUrl", manager.SourceControlService.DeleteWorkspace_TfsUrl);
        }

        [Fact, TempUserPath]
        public void EachCallGetsUniqueWorkspace()
        {
            NetworkCredential creds = new NetworkCredential("joe", "bob");
            TestableTfsWorkspaceManager manager = TestableTfsWorkspaceManager.Create();
            string name1, name2;

            using (TfsWorkspace workspace1 = manager.CreateWorkspace("http://tfsUrl", creds))
            using (TfsWorkspace workspace2 = manager.CreateWorkspace("http://tfsUrl", creds))
            {
                name1 = workspace1.Name;
                name2 = workspace2.Name;
            }

            Assert.NotEqual(name1, name2);
        }

        [Fact, TempUserPath]
        public void SecondManagerWontDeleteWorkspacesOpenInFirstManager()
        {
            NetworkCredential creds = new NetworkCredential("joe", "bob");
            TestableTfsWorkspaceManager manager1 = TestableTfsWorkspaceManager.Create();
            TestableTfsWorkspaceManager manager2 = TestableTfsWorkspaceManager.Create();
            string workspaceName1, workspaceName2;

            using (TfsWorkspace workspace1 = manager1.CreateWorkspace("http://tfsUrl", creds))
            using (TfsWorkspace workspace2 = manager2.CreateWorkspace("http://tfsUrl", creds))
            {
                workspaceName1 = workspace1.Name;
                workspaceName2 = workspace2.Name;

                Assert.Null(manager2.SourceControlService.DeleteWorkspace_TfsUrl);
            }

            Assert.Equal("http://tfsUrl", manager1.SourceControlService.DeleteWorkspace_TfsUrl);
            Assert.Equal(workspaceName1, manager1.SourceControlService.DeleteWorkspace_WorkspaceName);
            Assert.Equal("http://tfsUrl", manager2.SourceControlService.DeleteWorkspace_TfsUrl);
            Assert.Equal(workspaceName2, manager2.SourceControlService.DeleteWorkspace_WorkspaceName);
        }

        class TempUserPathAttribute : BeforeAfterTestAttribute
        {
            string tempPath;

            public override void After(MethodInfo methodUnderTest)
            {
                Directory.Delete(tempPath, true);
            }

            public override void Before(MethodInfo methodUnderTest)
            {
                tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
                fileSystem.EnsurePath(tempPath);
                fileSystem.UserDataPath = tempPath;
            }
        }

        class TestableTfsWorkspaceManager : TfsWorkspaceManager
        {
            public readonly StubSourceControlService SourceControlService;

            TestableTfsWorkspaceManager(StubSourceControlService sourceControlService,
                                        IFileSystem fileSystem)
                : base(sourceControlService, fileSystem)
            {
                SourceControlService = sourceControlService;
            }

            public static TestableTfsWorkspaceManager Create()
            {
                return new TestableTfsWorkspaceManager(new StubSourceControlService(), fileSystem);
            }
        }
    }
}